home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / lynx-2.4 / WWW / Library / Implementation / HTTCP.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-28  |  23.8 KB  |  921 lines

  1. /*            Generic Communication Code        HTTCP.c
  2. **            ==========================
  3. **
  4. **    This code is in common between client and server sides.
  5. **
  6. **    16 Jan 92  TBL    Fix strtol() undefined on CMU Mach.
  7. **    25 Jun 92  JFG  Added DECNET option through TCP socket emulation.
  8. **    13 Sep 93  MD   Added correct return of vmserrorno for HTInetStatus.
  9. **            Added decoding of vms error message for MULTINET.
  10. **      7-DEC-1993 Bjorn S. Nilsson, ALEPH, CERN, VMS UCX ioctl() changes
  11. **            (done of Mosaic)
  12. **      19 Feb 94  Danny Mayer    Added Bjorn Fixes to Lynx version
  13. **     7 Mar 94  Danny Mayer  Added Fix UCX version for full domain name
  14. **    20 May 94  Andy Harper  Added support for CMU TCP/IP transport
  15. **    17 Nov 94  Andy Harper  Added support for SOCKETSHR transport
  16. */
  17.  
  18.  
  19. #include "HTUtils.h"
  20. #include "tcp.h"        /* Defines SHORT_NAMES if necessary */
  21. #include "HTAccess.h"
  22. #include "HTParse.h"
  23. #include "HTAlert.h"
  24.  
  25. #ifdef SVR4_BSDSELECT
  26. PUBLIC int BSDselect PARAMS((int nfds, fd_set * readfds, fd_set * writefds,
  27.                   fd_set * exceptfds, struct timeval * timeout));
  28. #ifdef select
  29. #undef select
  30. #endif /* select */
  31. #define select BSDselect
  32. #ifdef SOCKS
  33. #ifdef Rselect
  34. #undef Rselect
  35. #endif /* Rselect */
  36. #define Rselect BSDselect
  37. #endif /* SOCKS */
  38. #endif /* SVR4_BSDSELECT */
  39.  
  40. #include "LYLeaks.h"
  41.  
  42. #ifdef SHORT_NAMES
  43. #define HTInetStatus        HTInStat
  44. #define HTInetString         HTInStri
  45. #define HTParseInet        HTPaInet
  46. #endif
  47.  
  48. #ifndef FD_SETSIZE
  49. #if defined(UCX) || defined(SOCKETSHR_TCP) || defined(CMU_TCP)
  50. #define FD_SETSIZE 32
  51. #else
  52. #define FD_SETSIZE 256
  53. #endif /* Limit # sockets to 32 for UCX, BSN - also SOCKETSHR and CMU, AH */
  54. #endif
  55.  
  56. /*    Module-Wide variables
  57. */
  58.  
  59. PRIVATE char *hostname=0;        /* The name of this host */
  60.  
  61.  
  62. /*    PUBLIC VARIABLES
  63. */
  64.  
  65. /* PUBLIC SockA HTHostAddress; */    /* The internet address of the host */
  66.                     /* Valid after call to HTHostName() */
  67.  
  68. /*    Encode INET status (as in sys/errno.h)              inet_status()
  69. **    ------------------
  70. **
  71. ** On entry,
  72. **    where        gives a description of what caused the error
  73. **    global errno    gives the error number in the unix way.
  74. **
  75. ** On return,
  76. **    returns        a negative status in the unix way.
  77. */
  78. #ifndef PCNFS
  79. #ifdef VMS
  80. #if !defined(MULTINET) && !defined(UCX) && !defined(WIN_TCP) && !defined(CMU_TCP) && !defined(SOCKETSHR_TCP)
  81. extern int uerrno;    /* Deposit of error info (as per errno.h) */
  82. extern volatile noshare int socket_errno; /* socket VMS error info 
  83.                                              (used for translation of vmserrno) */
  84. extern volatile noshare int vmserrno;    /* Deposit of VMS error info */
  85. extern volatile noshare int errno;  /* noshare to avoid PSECT conflict */
  86. #endif /* not MULTINET */
  87. #else /* VMS */
  88. #ifndef errno
  89. extern int errno;
  90. #endif /* errno */
  91. #endif /* VMS */
  92.  
  93. #ifndef VM
  94. #ifndef VMS
  95. #ifndef NeXT
  96. #ifndef THINK_C
  97. #ifndef __NetBSD__
  98. extern char *sys_errlist[];        /* see man perror on cernvax */
  99. extern int sys_nerr;
  100. #endif    /* __NetBSD__ */
  101. #endif  /* think c */
  102. #endif    /* NeXT */
  103. #endif  /* VMS */
  104. #endif    /* VM */
  105.  
  106. #endif    /* PCNFS */
  107.  
  108. #ifdef UCX
  109. /*
  110.  * A routine to mimick the ioctl function for UCX.
  111.  * Bjorn S. Nilsson, 25-Nov-1993. Based on an example in the UCX manual.
  112.  */
  113. #include <iodef.h>
  114. #define IOC_OUT (int)0x40000000
  115. extern int vaxc$get_sdc(), sys$qiow();
  116.  
  117. PUBLIC int ioctl ARGS3
  118.     (int,    d, 
  119.     int,    request,
  120.     int *, argp)
  121. {
  122.   int sdc, status;
  123.   unsigned short fun, iosb[4];
  124.   char *p5, *p6;
  125.   struct comm
  126.     {
  127.       int command;
  128.       char *addr;
  129.     } ioctl_comm;
  130.   struct it2
  131.     {
  132.       unsigned short len;
  133.       unsigned short opt;
  134.       struct comm *addr;
  135.     } ioctl_desc;
  136.   if ((sdc = vaxc$get_sdc (d)) == 0)
  137.     {
  138.       errno = EBADF;
  139.       return -1;
  140.     }
  141.   ioctl_desc.opt  = UCX$C_IOCTL;
  142.   ioctl_desc.len  = sizeof(struct comm);
  143.   ioctl_desc.addr = &ioctl_comm;
  144.   if (request & IOC_OUT)
  145.     {
  146.       fun = IO$_SENSEMODE;
  147.       p5 = 0;
  148.       p6 = (char *)&ioctl_desc;
  149.     }
  150.   else
  151.     {
  152.       fun = IO$_SETMODE;
  153.       p5 = (char *)&ioctl_desc;
  154.       p6 = 0;
  155.     }
  156.   ioctl_comm.command = request;
  157.   ioctl_comm.addr = (char *)argp;
  158.   status = sys$qiow (0, sdc, fun, iosb, 0, 0,
  159.     0, 0, 0, 0, p5, p6);
  160.   if (!(status & 01))
  161.     {
  162.       errno = status;
  163.       return -1;
  164.     }
  165.   if (!(iosb[0] & 01))
  166.     {
  167.       errno = iosb[0];
  168.       return -1;
  169.     }
  170.   return 0;
  171. }
  172. #include <perror.h> /* RJF */
  173. #endif /* VMS, UCX, BSN */
  174.  
  175.  
  176. /*    Report Internet Error
  177. **    ---------------------
  178. */
  179. #ifdef __STDC__
  180. PUBLIC int HTInetStatus(char *where)
  181. #else
  182. PUBLIC int HTInetStatus(where)
  183.     char    *where;
  184. #endif
  185. {
  186. #ifdef VMS
  187. #ifdef MULTINET
  188.             SOCKET_ERRNO = vmserrno;
  189. #endif
  190. #endif 
  191.  
  192.     CTRACE(tfp,
  193.         "TCP: Error %d in `SOCKET_ERRNO' after call to %s() failed.\n\t%s\n",
  194.     SOCKET_ERRNO,  where, /* third arg is transport/platform specific */
  195.  
  196. #ifdef VM
  197.         "(Error number not translated)");    /* What Is the VM equiv? */
  198. #define ER_NO_TRANS_DONE
  199. #endif
  200. #ifdef VMS
  201. #ifdef MULTINET
  202.             vms_errno_string());
  203. #else
  204.         "(Error number not translated)");
  205. #endif
  206. #define ER_NO_TRANS_DONE
  207. #endif
  208. #ifdef NeXT
  209.         strerror(errno));
  210. #define ER_NO_TRANS_DONE
  211. #endif
  212. #ifdef THINK_C
  213.         strerror(errno));
  214. #define ER_NO_TRANS_DONE
  215. #endif
  216.  
  217. #ifndef ER_NO_TRANS_DONE
  218.         errno < sys_nerr ? sys_errlist[errno] : "Unknown error" );
  219. #endif
  220.  
  221. #ifdef VMS
  222. #ifndef MULTINET
  223.     CTRACE(tfp, "         Unix error number (errno) = %ld dec\n", errno);
  224.     CTRACE(tfp, "         VMS error (vaxc$errno)    = %lx hex\n", vaxc$errno);
  225. #endif
  226. #endif
  227.  
  228. #ifdef VMS
  229.     /* uerrno and errno happen to be zero if vmserrno <> 0 */
  230. #ifdef MULTINET
  231.     return -vmserrno;
  232. #else
  233.     return -vaxc$errno;
  234. #endif
  235. #else
  236.     return -errno;
  237. #endif
  238. }
  239.  
  240.  
  241. /*    Parse a cardinal value                       parse_cardinal()
  242. **    ----------------------
  243. **
  244. ** On entry,
  245. **    *pp        points to first character to be interpreted, terminated by
  246. **            non 0:9 character.
  247. **    *pstatus    points to status already valid
  248. **    maxvalue    gives the largest allowable value.
  249. **
  250. ** On exit,
  251. **    *pp        points to first unread character
  252. **    *pstatus    points to status updated iff bad
  253. */
  254.  
  255. PUBLIC unsigned int HTCardinal ARGS3
  256.     (int *,        pstatus,
  257.     char **,    pp,
  258.     unsigned int,    max_value)
  259. {
  260.     int   n;
  261.     if ( (**pp<'0') || (**pp>'9')) {        /* Null string is error */
  262.     *pstatus = -3;  /* No number where one expeceted */
  263.     return 0;
  264.     }
  265.  
  266.     n=0;
  267.     while ((**pp>='0') && (**pp<='9')) n = n*10 + *((*pp)++) - '0';
  268.  
  269.     if (n>max_value) {
  270.     *pstatus = -4;  /* Cardinal outside range */
  271.     return 0;
  272.     }
  273.  
  274.     return n;
  275. }
  276.  
  277.  
  278. #ifndef DECNET  /* Function only used below for a trace message */
  279.  
  280. /*    Produce a string for an Internet address
  281. **    ----------------------------------------
  282. **
  283. ** On exit,
  284. **    returns    a pointer to a static string which must be copied if
  285. **        it is to be kept.
  286. */
  287.  
  288. PUBLIC CONST char * HTInetString ARGS1(SockA*,sin)
  289. {
  290.     static char string[16];
  291.     sprintf(string, "%d.%d.%d.%d",
  292.         (int)*((unsigned char *)(&sin->sin_addr)+0),
  293.         (int)*((unsigned char *)(&sin->sin_addr)+1),
  294.         (int)*((unsigned char *)(&sin->sin_addr)+2),
  295.         (int)*((unsigned char *)(&sin->sin_addr)+3));
  296.     return string;
  297. }
  298. #endif /* Decnet */
  299.  
  300.  
  301. /*    Parse a network node address and port
  302. **    -------------------------------------
  303. **
  304. ** On entry,
  305. **    str    points to a string with a node name or number,
  306. **        with optional trailing colon and port number.
  307. **    sin    points to the binary internet or decnet address field.
  308. **
  309. ** On exit,
  310. **    *sin    is filled in. If no port is specified in str, that
  311. **        field is left unchanged in *sin.
  312. */
  313. PUBLIC int HTParseInet ARGS2(SockA *,sin, CONST char *,str)
  314. {
  315.     char *port;
  316.     char host[256];
  317.     struct hostent  *phost;    /* Pointer to host - See netdb.h */
  318.     strcpy(host, str);        /* Take a copy we can mutilate */
  319.  
  320.  
  321.  
  322. /*    Parse port number if present
  323. */    
  324.     if (port=strchr(host, ':')) {
  325.         *port++ = 0;        /* Chop off port */
  326.         if (port[0]>='0' && port[0]<='9') {
  327.  
  328. #ifdef unix
  329.         sin->sin_port = htons(atol(port));
  330. #else /* VMS */
  331. #ifdef DECNET
  332.         sin->sdn_objnum = (unsigned char) (strtol(port, (char**)0 , 10));
  333. #else
  334.         sin->sin_port = htons(strtol(port, (char**)0 , 10));
  335. #endif /* Decnet */
  336. #endif /* Unix vs. VMS */
  337.  
  338.     } else {
  339.  
  340. #ifdef SUPPRESS        /* 1. crashes!?!.  2. Not recommended */
  341.         struct servent * serv = getservbyname(port, (char*)0);
  342.         if (serv) sin->sin_port = serv->s_port;
  343.         else if (TRACE) fprintf(stderr, "TCP: Unknown service %s\n", port);
  344. #endif
  345.     }
  346.       }
  347.  
  348. #ifdef DECNET
  349.     /* read Decnet node name. @@ Should know about DECnet addresses, but it's
  350.        probably worth waiting until the Phase transition from IV to V. */
  351.  
  352.     sin->sdn_nam.n_len = min(DN_MAXNAML, strlen(host));  /* <=6 in phase 4 */
  353.     strncpy (sin->sdn_nam.n_name, host, sin->sdn_nam.n_len + 1);
  354.  
  355.     if (TRACE) fprintf(stderr,  
  356.     "DECnet: Parsed address as object number %d on host %.6s...\n",
  357.               sin->sdn_objnum, host);
  358.  
  359. #else  /* parse Internet host */
  360.  
  361. /*    Parse host number if present.
  362. */  
  363.     if (*host>='0' && *host<='9') {   /* Numeric node address: */
  364. #ifdef DGUX_OLD
  365.     sin->sin_addr.s_addr = inet_addr(host).s_addr;    /* See arpa/inet.h */
  366. #else
  367.     sin->sin_addr.s_addr = inet_addr(host);        /* See arpa/inet.h */
  368. #endif /* DGUX_OLD */
  369.  
  370.     } else {            /* Alphanumeric node name: */
  371. #ifdef MVS    /* Oustanding problem with crash in MVS gethostbyname */
  372.     if(TRACE)fprintf(stderr, "HTTCP: Calling gethostbyname(%s)\n", host);
  373. #endif
  374.     phost=gethostbyname(host);    /* See netdb.h */
  375. #ifdef MVS
  376.     if(TRACE)fprintf(stderr, "HTTCP: gethostbyname() returned %d\n", phost);
  377. #endif
  378.     if (!phost) {
  379.         if (TRACE) fprintf(stderr, 
  380.             "HTTPAccess: Can't find internet node name `%s'.\n",host);
  381.         return -1;  /* Fail? */
  382.     }
  383.     memcpy((void *)&sin->sin_addr, phost->h_addr, phost->h_length);
  384.     }
  385.  
  386.     if (TRACE) fprintf(stderr,  
  387.     "TCP: Parsed address as port %d, IP address %d.%d.%d.%d\n",
  388.         (int)ntohs(sin->sin_port),
  389.         (int)*((unsigned char *)(&sin->sin_addr)+0),
  390.         (int)*((unsigned char *)(&sin->sin_addr)+1),
  391.         (int)*((unsigned char *)(&sin->sin_addr)+2),
  392.         (int)*((unsigned char *)(&sin->sin_addr)+3));
  393.  
  394. #endif  /* Internet vs. Decnet */
  395.  
  396.     return 0;    /* OK */
  397. }
  398.  
  399.  
  400. /*    Derive the name of the host on which we are
  401. **    -------------------------------------------
  402. **
  403. */
  404. #ifdef __STDC__
  405. PRIVATE void get_host_details(void)
  406. #else
  407. PRIVATE void get_host_details()
  408. #endif
  409.  
  410. #ifndef MAXHOSTNAMELEN
  411. #define MAXHOSTNAMELEN 64        /* Arbitrary limit */
  412. #endif
  413.  
  414. {
  415.     char name[MAXHOSTNAMELEN+1];    /* The name of this host */
  416. #ifdef UCX
  417.     char *domain_name;                   /* The name of this host domain */
  418. #endif
  419. #ifdef NEED_HOST_ADDRESS        /* no -- needs name server! */
  420.     struct hostent * phost;        /* Pointer to host -- See netdb.h */
  421. #endif
  422.     int namelength = sizeof(name);
  423.     
  424.     if (hostname) return;        /* Already done */
  425.     gethostname(name, namelength);    /* Without domain */
  426.     StrAllocCopy(hostname, name);
  427. #ifdef UCX
  428.     /*  UCX doesn't give the complete domain name. get rest from UCX$BIND_DOM
  429.     **  Logical
  430.     */
  431.     if(strchr(hostname,'.') == NULL) {           /* Not full address */
  432.         domain_name = getenv("UCX$BIND_DOMAIN");
  433.         if(domain_name != NULL) {
  434.             StrAllocCat(hostname, ".");
  435.             StrAllocCat(hostname, domain_name);
  436.         }
  437.      }
  438. #endif /* UCX */
  439.     CTRACE(tfp, "TCP: Local host name is %s\n", hostname);
  440.  
  441. #ifndef DECNET  /* Decnet ain't got no damn name server 8#OO */
  442. #ifdef NEED_HOST_ADDRESS         /* no -- needs name server! */
  443.     phost=gethostbyname(name);         /* See netdb.h */
  444.     if (!phost) {
  445.     if (TRACE) fprintf(stderr, 
  446.         "TCP: Can't find my own internet node address for `%s'!!\n",
  447.         name);
  448.     return;  /* Fail! */
  449.     }
  450.     StrAllocCopy(hostname, phost->h_name);
  451.     memcpy(&HTHostAddress, &phost->h_addr, phost->h_length);
  452.     if (TRACE) fprintf(stderr, "     Name server says that I am `%s' = %s\n",
  453.         hostname, HTInetString(&HTHostAddress));
  454. #endif
  455.  
  456. #endif /* not Decnet */
  457. }
  458.  
  459. #ifdef __STDC__
  460. PUBLIC const char * HTHostName(void)
  461. #else
  462. PUBLIC char * HTHostName()
  463. #endif
  464. {
  465.     get_host_details();
  466.     return hostname;
  467. }
  468.  
  469. /*
  470.  * interruptable connect as implemented by Marc Andreesen and
  471.  * hacked in by Lou Montulli
  472.  */ 
  473.  
  474. PUBLIC int HTDoConnect ARGS4(char *,url, char *,protocol, int,default_port, 
  475.                                      int *,s)
  476. {
  477.   struct sockaddr_in soc_address;
  478.   struct sockaddr_in *sin = &soc_address;
  479.   int status;
  480.  
  481.   /* Set up defaults: */
  482.   sin->sin_family = AF_INET;
  483.   sin->sin_port = htons(default_port);
  484.  
  485.   /* Get node name and optional port number: */
  486.   {
  487.     char line[256];
  488.     char *p1 = HTParse(url, "", PARSE_HOST);
  489.     char *at_sign, *host;
  490.     int status;
  491.  
  492.     /* if theres an @ then use the stuff after it as a hostname */
  493.     if((at_sign = strchr(p1,'@')) != NULL)
  494.     host = at_sign+1;
  495.     else
  496.     host = p1;
  497.  
  498.     sprintf (line, "Looking up %s.", host);
  499.     _HTProgress (line);
  500.  
  501.     status = HTParseInet(sin, host);
  502.     if (status)
  503.       {
  504.         sprintf (line, "Unable to locate remote host %s.", host);
  505.         _HTProgress(line);
  506.         free (p1);
  507.         return HT_NO_DATA;
  508.       }
  509.  
  510.     sprintf (line, "Making %s connection to %s.", protocol, host);
  511.     _HTProgress (line);
  512.     free (p1);
  513.   }
  514.  
  515.   /* Now, let's get a socket set up from the server for the data: */
  516.   *s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  517.  
  518.   /*
  519.    * Make the socket non-blocking, so the connect can be canceled.
  520.    * This means that when we issue the connect we should NOT
  521.    * have to wait for the accept on the other end.
  522.    */
  523. #if !defined(NO_IOCTL)
  524.   {
  525.     int ret;
  526.     int val = 1;
  527.     char line[256];
  528.  
  529.     ret = IOCTL(*s, FIONBIO, &val);
  530.     if (ret == -1)
  531.       {
  532.         sprintf (line, "Could not make connection non-blocking.");
  533.         _HTProgress(line);
  534.       }
  535.   }
  536. #endif /* not NO_IOCTL */
  537. #if defined(USE_FCNTL)
  538.   {
  539.     int ret;
  540.     char line[256];
  541.  
  542.     ret = fcntl(*s, F_SETFL, O_NONBLOCK);
  543.     if (ret == -1)
  544.       {
  545.         sprintf (line, "Could not make connection non-blocking.");
  546.         _HTProgress(line);
  547.       }
  548.   }
  549. #endif /* USE_FCNTL */
  550.  
  551.   /*
  552.    * Issue the connect.  Since the server can't do an instantaneous accept
  553.    * and we are non-blocking, this will almost certainly return a negative
  554.    * status.
  555.    */
  556. #ifdef SOCKS
  557.   status = Rconnect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address));
  558. #else
  559.   status = connect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address));
  560. #endif /* SOCKS */
  561.  
  562.   /*
  563.    * According to the Sun man page for connect:
  564.    *     EINPROGRESS         The socket is non-blocking and the  con-
  565.    *                         nection cannot be completed immediately.
  566.    *                         It is possible to select(2) for  comple-
  567.    *                         tion  by  selecting the socket for writ-
  568.    *                         ing.
  569.    * According to the Motorola SVR4 man page for connect:
  570.    *     EAGAIN              The socket is non-blocking and the  con-
  571.    *                         nection cannot be completed immediately.
  572.    *                         It is possible to select for  completion
  573.    *                         by  selecting  the  socket  for writing.
  574.    *                         However, this is only  possible  if  the
  575.    *                         socket  STREAMS  module  is  the topmost
  576.    *                         module on  the  protocol  stack  with  a
  577.    *                         write  service  procedure.  This will be
  578.    *                         the normal case.
  579.    */
  580. #ifdef SVR4
  581.   if ((status < 0) && ((SOCKET_ERRNO == EINPROGRESS)||(SOCKET_ERRNO == EAGAIN)))
  582. #else
  583.   if ((status < 0) && (SOCKET_ERRNO == EINPROGRESS))
  584. #endif /* SVR4 */
  585.     {
  586.       struct timeval timeout;
  587.       int ret;
  588.       int tries=0;
  589.  
  590.       timeout.tv_sec = 0;
  591.     /*
  592.      *    Increased for Linux v1.1.20 users.
  593.      *    Thanks to tin@saigon.com
  594.      */
  595.       timeout.tv_usec = 300000;
  596.       ret = 0;
  597.       while (ret <= 0)
  598.         {
  599.           fd_set writefds;
  600.           int intr=0;
  601.  
  602.       /*
  603.        *  Protect against an infinite loop.
  604.        */
  605.       if (tries++ >= 5000) {
  606.           HTAlert("Connection failed for 5000 tries.");
  607.            return HT_NO_DATA;
  608.       }
  609.  
  610.           FD_ZERO(&writefds);
  611.           FD_SET(*s, &writefds);
  612. #if defined(__hpux) || defined(VMS)
  613. #ifdef SOCKS
  614.           ret = Rselect(FD_SETSIZE, NULL, (int *)&writefds, NULL, &timeout);
  615. #else
  616.           ret = select(FD_SETSIZE, NULL, (int *)&writefds, NULL, &timeout);
  617. #endif /* SOCKS */
  618. #else
  619. #ifdef SOCKS
  620.           ret = Rselect(FD_SETSIZE, NULL, &writefds, NULL, &timeout);
  621. #else
  622.           ret = select(FD_SETSIZE, NULL, &writefds, NULL, &timeout);
  623. #endif /* SOCKS */
  624. #endif /* __hpux || VMS */
  625.           /*
  626.            * Again according to the Sun and Motorola man pagse for connect:
  627.            *     EALREADY            The socket is non-blocking and a  previ-
  628.            *                         ous  connection attempt has not yet been
  629.            *                         completed.
  630.            * Thus if the SOCKET_ERRNO is NOT EALREADY we have a real error, and
  631.            * should break out here and return that error.
  632.            * Otherwise if it is EALREADY keep on trying to complete the
  633.            * connection.
  634.            */
  635.           if ((ret < 0)&&(SOCKET_ERRNO != EALREADY))
  636.             {
  637.               status = ret;
  638.               break;
  639.             }
  640.           else if (ret > 0)
  641.             {
  642.               /*
  643.                * Extra check here for connection success, if we try to connect
  644.                * again, and get EISCONN, it means we have a successful
  645.                * connection.
  646.                */
  647. #ifdef SOCKS
  648.               status = Rconnect(*s, (struct sockaddr*)&soc_address,
  649.                                 sizeof(soc_address));
  650. #else
  651.               status = connect(*s, (struct sockaddr*)&soc_address,
  652.                                sizeof(soc_address));
  653. #endif /* SOCKS */
  654. #ifndef UCX
  655.               if ((status < 0)&&(SOCKET_ERRNO == EISCONN))
  656. #else
  657. /*
  658.  * A UCX feature: Instead of returning EISCONN UCX returns EADDRINUSE.
  659.  * Test for this status also.
  660.  */
  661.               if ((status < 0)&&((SOCKET_ERRNO == EISCONN) ||
  662.                  (SOCKET_ERRNO == EADDRINUSE)))
  663. #endif /* VMS, UCX, BSN */
  664.                 {
  665.                   status = 0;
  666.                 }
  667.  
  668.           if (SOCKET_ERRNO == EALREADY)  /* new stuff LJM */
  669.           ret=0; /* keep going */
  670.           else
  671.                   break;
  672.             }
  673.           /*
  674.            * The select says we aren't ready yet.
  675.            * Try to connect again to make sure.  If we don't get EALREADY
  676.            * or EISCONN, something has gone wrong.  Break out and report it.
  677.            * For some reason SVR4 returns EAGAIN here instead of EALREADY,
  678.            * even though the man page says it should be EALREADY.
  679.            */
  680.           else
  681.             {
  682. #ifdef SOCKS
  683.               status = Rconnect(*s, (struct sockaddr*)&soc_address,
  684.                                 sizeof(soc_address));
  685. #else
  686.               status = connect(*s, (struct sockaddr*)&soc_address,
  687.                                  sizeof(soc_address));
  688. #endif /* SOCKS */
  689. #if defined(SVR4)
  690.               if ((status < 0)&&(SOCKET_ERRNO != EALREADY)&&
  691.             (SOCKET_ERRNO != EAGAIN)&&(SOCKET_ERRNO != EISCONN))
  692. #else
  693. #ifndef UCX
  694.               if ((status < 0)&&(SOCKET_ERRNO != EALREADY)&&
  695.                         (SOCKET_ERRNO != EISCONN))
  696. #else
  697.               /*
  698.                * UCX pre 3 apparently returns errno = 18242 instead of
  699.                * any of the EALREADY or EISCONN values.
  700.                */
  701.                if ((status < 0)&&(SOCKET_ERRNO != EALREADY)&&
  702.                  (SOCKET_ERRNO != EISCONN)&&
  703.                            (SOCKET_ERRNO != 18242))
  704. #endif /* UCX, BSN */
  705. #endif /* SVR4 */
  706.                 {
  707.                   break;
  708.                 }
  709.             }
  710.           if(HTCheckForInterrupt())
  711.             {
  712.               if (TRACE)
  713.                 fprintf (stderr, "*** INTERRUPTED in middle of connect.\n");
  714.               status = HT_INTERRUPTED;
  715.               SOCKET_ERRNO = EINTR;
  716.               break;
  717.             }
  718.         }
  719.     }
  720.  
  721.   /*
  722.    * Make the socket blocking again on good connect
  723.    */
  724.   if (status >= 0)
  725.     {
  726. #if !defined(NO_IOCTL)
  727.       int ret;
  728.       int val = 0;
  729.       char line[256];
  730.  
  731.       ret = IOCTL(*s, FIONBIO, &val);
  732.       if (ret == -1)
  733.         {
  734.           sprintf (line, "Could not restore socket to blocking.");
  735.           _HTProgress(line);
  736.         }
  737. #endif /* not NO_IOCTL */
  738. #if defined(USE_FCNTL)
  739.   {
  740.     int ret;
  741.     char line[256];
  742.  
  743.     ret = fcntl(*s, F_SETFL, 0);
  744.     if (ret == -1)
  745.       {
  746.         sprintf (line, "Could not restore socket to blocking.");
  747.         _HTProgress(line);
  748.       }
  749.   }
  750. #endif /* USE_FCNTL */
  751.     }
  752.   /*
  753.    * Else the connect attempt failed or was interrupted.
  754.    * so close up the socket.
  755.    */
  756.   else
  757.     {
  758.         NETCLOSE(*s);
  759.     }
  760.  
  761.   return status;
  762. }
  763.  
  764. /* This is so interruptible reads can be implemented cleanly. */
  765. int HTDoRead ARGS3(int,fildes, void *,buf, unsigned,nbyte)
  766. {
  767.   int ready, ret, intr=0;
  768.   fd_set readfds;
  769.   struct timeval timeout;
  770.   int tries=0;
  771. #ifdef UCX
  772.   int nb;
  773. #endif /* UCX, BSN */
  774.  
  775.   if (fildes <= 0)
  776.       return -1;
  777.  
  778.   if (HTCheckForInterrupt())
  779.     {
  780.         SOCKET_ERRNO = EINTR;
  781.         return (HT_INTERRUPTED);
  782.     }
  783.  
  784.  
  785.   timeout.tv_sec = 0;
  786.   timeout.tv_usec = 100000;
  787.  
  788. #if !defined(NO_IOCTL)
  789.   ready = 0;
  790. #else
  791.   ready = 1;
  792. #endif /* bypass for NO_IOCTL */
  793.   while (!ready)
  794.     {
  795.     /*
  796.      *  Protect against an infinite loop.
  797.      */
  798.     if (tries++ >= 5000) {
  799.         HTAlert("Socket read failed for 5000 tries.");
  800.         SOCKET_ERRNO = EINTR;
  801.         return HT_INTERRUPTED;
  802.     }
  803.  
  804.         FD_ZERO(&readfds);
  805.         FD_SET(fildes, &readfds);
  806. #if defined(__hpux) || defined(VMS)
  807. #ifdef SOCKS
  808.         ret = Rselect(FD_SETSIZE, (int *)&readfds, NULL, NULL, &timeout);
  809. #else
  810.         ret = select(FD_SETSIZE, (int *)&readfds, NULL, NULL, &timeout);
  811. #endif /* SOCKS */
  812. #else
  813. #ifdef SOCKS
  814.         ret = Rselect(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
  815. #else
  816.         ret = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
  817. #endif /* SOCKS */
  818. #endif
  819.         if (ret < 0)
  820.           {
  821.                 return -1;
  822.           }
  823.         else if (ret > 0)
  824.           {
  825.                 ready = 1;
  826.           }
  827.         else if(HTCheckForInterrupt())
  828.           {
  829.                    SOCKET_ERRNO = EINTR;
  830.                 return HT_INTERRUPTED;
  831.           }
  832.     }
  833.  
  834. #if !defined(UCX) || !defined(VAXC)
  835.   return SOCKET_READ (fildes, buf, nbyte);
  836. #else                           /* VAXC and UCX problem only */
  837.   errno = vaxc$errno = 0;
  838.   nb = SOCKET_READ (fildes, buf, nbyte);
  839.   CTRACE(tfp, "Read - nb,errno,vaxc$errno: %d %d %d\n", nb,errno,vaxc$errno);
  840.   if ((nb <= 0) && TRACE)
  841.      perror ("HTTCP.C:HTDoRead:read");          /* RJF */
  842.   /*
  843.    * An errno value of EPIPE and nb < 0 indicates end-of-file on VAXC
  844.    */
  845.   if ((nb <= 0) && (errno == EPIPE)) {
  846.        nb = 0;
  847.        errno = 0;
  848.   }
  849.   return nb;
  850. #endif /* UCX, BSN */
  851. }
  852.  
  853. #ifdef SVR4_BSDSELECT
  854. /*
  855.  *  This is a fix for the difference between BSD's select() and
  856.  *  SVR4's select().  SVR4's select() can never return a value larger
  857.  *  than the total number of file descriptors being checked.  So, if
  858.  *  you select for read and write on one file descriptor, and both
  859.  *  are true, SVR4 select() will only return 1.  BSD select in the
  860.  *  same situation will return 2.
  861.  *
  862.  *    Additionally, BSD select() on timing out, will zero the masks,
  863.  *    while SVR4 does not.  This is fixed here as well.
  864.  *
  865.  *    Set your tabstops to 4 characters to have this code nicely formatted.
  866.  *
  867.  *    Jerry Whelan, guru@bradley.edu, June 12th, 1993
  868.  */
  869. #ifdef select
  870. #undef select
  871. #endif /* select */
  872.  
  873. #ifdef SOCKS
  874. #ifdef Rselect
  875. #undef Rselect
  876. #endif /* Rselect */
  877. #endif /* SOCKS */
  878.  
  879. #include <sys/types.h>
  880. #include <sys/time.h>
  881. #include <sys/select.h>
  882.  
  883.  
  884. PUBLIC int BSDselect ARGS5 (int,nfds, fd_set *,readfds,fd_set *,writefds,
  885.                  fd_set *,exceptfds, struct timeval *,timeout)
  886. {
  887.     int        rval,
  888.             i;
  889.  
  890. #ifdef SOCKS
  891.     rval = Rselect(nfds, readfds, writefds, exceptfds, timeout);
  892. #else
  893.     rval = select(nfds, readfds, writefds, exceptfds, timeout);
  894. #endif /* SOCKS */
  895.  
  896.     switch(rval) {
  897.         case -1:    return(rval);
  898.                     break;
  899.  
  900.         case 0:        if(readfds != NULL)
  901.                         FD_ZERO(readfds);
  902.                     if(writefds != NULL)
  903.                         FD_ZERO(writefds);
  904.                     if(exceptfds != NULL)
  905.                         FD_ZERO(exceptfds);
  906.  
  907.                     return(rval);
  908.                     break;
  909.  
  910.         default:    for(i=0, rval=0; i < nfds; i++) {
  911.         if((readfds != NULL) && FD_ISSET(i, readfds)) rval++;
  912.         if((writefds != NULL) && FD_ISSET(i, writefds)) rval++;
  913.         if((exceptfds != NULL) && FD_ISSET(i, exceptfds)) rval++;
  914.  
  915.                     }
  916.                     return(rval);
  917.         }
  918. /* Should never get here */
  919. }
  920. #endif /* SVR4_BSDSELECT */
  921.